﻿#include "ConquestObject.h"
#include "../../Shared/Globals.h"
#include "../../Shared/Functions/Functions.h"
#include "../Settings.h"
#include "../MirDatabase/MonsterInfo.h"
#include "../../Shared/ServerPackets.h"
#include "MonsterObject.h"
#include "../../Shared/Data/Stat.h"
#include "../MirDatabase/NPCInfo.h"

using namespace Server::MirEnvir;
using namespace Server::MirDatabase;
using namespace Server::MirObjects::Monsters;

namespace Server::MirObjects
{

    Server::MirEnvir::Envir *ConquestObject::getEnvir()
    {
        return Envir::getMain();
    }

    ConquestObject::ConquestObject()
    {

    }

    ConquestObject::ConquestObject(PlayerObject *owner, const std::string &name)
    {

    }

    ConquestObject::ConquestObject(BinaryReader *reader)
    {
        Owner = reader->ReadInt32();
        ArcherCount = reader->ReadInt32();
        for (int i = 0; i < ArcherCount; i++)
        {
            ConquestArcherObject tempVar(reader);
            ArcherList.push_back(&tempVar);
        }
        GateCount = reader->ReadInt32();
        for (int i = 0; i < GateCount; i++)
        {
            ConquestGateObject tempVar2(reader);
            GateList.push_back(&tempVar2);
        }
        WallCount = reader->ReadInt32();
        for (int i = 0; i < WallCount; i++)
        {
            ConquestWallObject tempVar3(reader);
            WallList.push_back(&tempVar3);
        }
        SiegeCount = reader->ReadInt32();
        for (int i = 0; i < SiegeCount; i++)
        {
            ConquestSiegeObject tempVar4(reader);
            SiegeList.push_back(&tempVar4);
        }
        GoldStorage = reader->ReadUInt32();
        npcRate = reader->ReadByte();
        AttackerID = reader->ReadInt32();
    }

    void ConquestObject::Save(BinaryWriter *writer)
    {
        writer->Write(Owner);
        writer->Write(ArcherList.size());
        for (int i = 0; i < ArcherList.size(); i++)
        {
            ArcherList[i]->Save(writer);
        }
        writer->Write(GateList.size());
        for (int i = 0; i < GateList.size(); i++)
        {
            GateList[i]->Save(writer);
        }
        writer->Write(WallList.size());
        for (int i = 0; i < WallList.size(); i++)
        {
            WallList[i]->Save(writer);
        }
        writer->Write(SiegeList.size());
        for (int i = 0; i < SiegeList.size(); i++)
        {
            SiegeList[i]->Save(writer);
        }
        writer->Write(GoldStorage);
        writer->Write(npcRate);
        writer->Write(AttackerID);
    }

    bool ConquestObject::getWarIsOn() const
    {
        return AtWar;
    }

    void ConquestObject::setWarIsOn(bool value)
    {
        AtWar = value;
        AtWarChanged();
    }

    void ConquestObject::LoadArchers()
    {
        for (int i = 0; i < ArcherList.size(); i++)
        {
            ArcherList[i]->Spawn();
        }
    }

    void ConquestObject::LoadGates()
    {
        for (int i = 0; i < GateList.size(); i++)
        {
            GateList[i]->Spawn(false);
        }
    }

    void ConquestObject::LoadWalls()
    {
        for (int i = 0; i < WallList.size(); i++)
        {
            WallList[i]->Spawn(false);
        }
    }

    void ConquestObject::LoadSieges()
    {
        for (int i = 0; i < SiegeList.size(); i++)
        {
            SiegeList[i]->Spawn();
        }
    }

    void ConquestObject::LoadFlags()
    {
        for (int i = 0; i < FlagList.size(); i++)
        {
            FlagList[i]->Spawn();
        }
    }

    void ConquestObject::LoadNPCs()
    {
        for (int i = 0; i < ConquestMap->NPCs.size(); i++)
        {
            if (ConquestMap->NPCs[i]->Info->Conquest == Info->Index)
            {
                ConquestMap->NPCs[i]->Conq = this;
                ConquestNPCs.push_back(ConquestMap->NPCs[i]);
            }
        }


        PalaceMap = getEnvir()->GetMap(Info->PalaceIndex);

        if (PalaceMap != nullptr)
        {
            for (int i = 0; i < PalaceMap->NPCs.size(); i++)
            {
                if (PalaceMap->NPCs[i]->Info->Conquest == Info->Index)
                {
                    PalaceMap->NPCs[i]->Conq = this;
                    ConquestNPCs.push_back(ConquestMap->NPCs[i]);
                }
            }

        }

        Map *temp;
        for (int i = 0; i < Info->ExtraMaps.size(); i++)
        {
            temp = getEnvir()->GetMap(Info->ExtraMaps[i]);
            if (temp == nullptr)
            {
                continue;
            }
            for (int j = 0; j < temp->NPCs.size(); j++)
            {
                if (temp->NPCs[j]->Info->Conquest == Info->Index)
                {
                    temp->NPCs[j]->Conq = this;
                    ConquestNPCs.push_back(temp->NPCs[j]);
                }
            }

        }
    }

    void ConquestObject::AtWarChanged()
    {
        if (getWarIsOn())
        {
            if (StartType == ConquestType::Forced)
            {
                WarStartTime = DateTime::Now;
                WarEndTime = WarStartTime.AddMinutes(Info->WarLength);
                GameType = Info->Game;
            }

            NPCVisibility(true);

            switch (GameType)
            {
                case ConquestGame::CapturePalace:
                    break;
                case ConquestGame::KingOfHill:
                    CreateZone(true);
                    break;
                case ConquestGame::Random:
                    break;
                case ConquestGame::Classic:
                    break;
            }

        }
        else
        {
            NPCVisibility(false);

            for (int i = 0; i < ArcherList.size(); i++)
            {
                if (ArcherList[i]->ArcherMonster != nullptr)
                {
                    ArcherList[i]->ArcherMonster.setTarget(nullptr);
                }
            }

            switch (StartType)
            {
                case ConquestType::Request:
                    AttackerID = -1;
                    break;

            }

            switch (GameType)
            {
                case ConquestGame::CapturePalace:
                    break;
                case ConquestGame::KingOfHill:
                    CreateZone(false);
                    break;
                case ConquestGame::Random:
                    break;
                case ConquestGame::Classic:
                    break;
            }
        }
    }

    void ConquestObject::NPCVisibility(bool Show)
    {
        //Check if Players in Conquest Zone;
        for (int j = 0; j < ConquestMap->Players.size(); j++)
        {
            ConquestMap->Players[j]->CheckConquest();
        }

        PalaceMap = getEnvir()->GetMap(Info->PalaceIndex);
        if (PalaceMap != nullptr)
        {
            if (Show)
            {
                PalaceMap->tempConquest = this;
            }
            else
            {
                PalaceMap->tempConquest = nullptr;
            }

            for (int j = 0; j < PalaceMap->Players.size(); j++)
            {
                PalaceMap->Players[j]->CheckConquest();
            }
        }

        Map *temp;
        for (int i = 0; i < Info->ExtraMaps.size(); i++)
        {
            temp = getEnvir()->GetMap(Info->ExtraMaps[i]);
            if (temp == nullptr)
            {
                continue;
            }

            if (Show)
            {
                temp->tempConquest = this;
            }
            else
            {
                temp->tempConquest = nullptr;
            }

            for (int k = 0; k < temp->Players.size(); k++)
            {
                temp->Players[k]->CheckConquest();
            }
        }


        //Set NPCs to invisible
        Map *npcMap;
        NPCObject *npcTemp;

        for (int i = 0; i < ConquestNPCs.size(); i++)
        {
            npcMap = ConquestNPCs[i]->getCurrentMap();
            npcTemp = ConquestNPCs[i];
            for (int j = 0; j < npcMap->Players.size(); j++)
            {
                if (Functions::InRange(npcTemp->getCurrentLocation(), npcMap->Players[j]->getCurrentLocation(), Globals::DataRange))
                {
                    npcTemp->CheckVisible(npcMap->Players[j]);
                }
            }

        }

    }

    bool ConquestObject::CheckDay()
    {
//C# TO C++ CONVERTER NOTE: The following 'switch' operated on a string and was converted to C++ 'if-else' logic:
//        switch (DateTime.Now.DayOfWeek.ToString())
//ORIGINAL LINE: case "Monday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        if (DateTime::Now.DayOfWeek.ToString() == "Monday")
        {
                return Info->Monday;
        }
//ORIGINAL LINE: case "Tuesday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        else if (DateTime::Now.DayOfWeek.ToString() == "Tuesday")
        {
                return Info->Tuesday;
        }
//ORIGINAL LINE: case "Wednesday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        else if (DateTime::Now.DayOfWeek.ToString() == "Wednesday")
        {
                return Info->Wednesday;
        }
//ORIGINAL LINE: case "Thursday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        else if (DateTime::Now.DayOfWeek.ToString() == "Thursday")
        {
                return Info->Thursday;
        }
//ORIGINAL LINE: case "Friday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        else if (DateTime::Now.DayOfWeek.ToString() == "Friday")
        {
                return Info->Friday;
        }
//ORIGINAL LINE: case "Saturday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        else if (DateTime::Now.DayOfWeek.ToString() == "Saturday")
        {
                return Info->Saturday;
        }
//ORIGINAL LINE: case "Sunday":
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        else if (DateTime::Now.DayOfWeek.ToString() == "Sunday")
        {
                return Info->Sunday;
        }

        return true;
    }

    void ConquestObject::AutoSchedule()
    {
        int start = ((Info->StartHour * 60));
        int finish = ((Info->StartHour * 60) + Info->WarLength);
        int now = ((DateTime::Now.Hour * 60) + DateTime::Now.Minute);

        if (getWarIsOn() && StartType == ConquestType::Forced && WarEndTime <= DateTime::Now)
        {
            EndWar(Info->Game);
        }

        if (StartType != ConquestType::Forced)
        {
            if (getWarIsOn() && (now > start && finish <= now))
            {
                EndWar(Info->Game);
            }
            else if (start <= now && finish > now && CheckDay())
            {
                if (!getWarIsOn())
                {
                    if (Info->Type == ConquestType::Request)
                    {
                        if (AttackerID != -1)
                        {
                            GameType = Info->Game;
                            StartType = Info->Type;
                            StartWar(Info->Game);
                        }
                    }
                    else
                    {
                        GameType = Info->Game;
                        StartType = Info->Type;
                        StartWar(Info->Game);
                    }

                }
            }
        }
        ScheduleTimer = getEnvir()->getTime() + Settings::Minute;
    }

    void ConquestObject::Process()
    {
        if (ScheduleTimer < getEnvir()->getTime())
        {
            AutoSchedule();
        }
        if (getWarIsOn() && (GameType == ConquestGame::KingOfHill || GameType == ConquestGame::Classic || GameType == ConquestGame::ControlPoints))
        {
            ScorePoints();
        }
    }

    void ConquestObject::Reset()
    {
        Owner = -1;
        AttackerID = -1;
        GoldStorage = 0;
        npcRate = 0;

        if (Guild != nullptr)
        {
            Guild->Conquest = nullptr;
            UpdatePlayers(Guild);
            Guild = nullptr;
        }

        for (int i = 0; i < ArcherList.size(); i++)
        {
            ArcherList[i]->Spawn();
        }

        for (int i = 0; i < GateList.size(); i++)
        {
            GateList[i]->Repair();
        }

        for (int i = 0; i < WallList.size(); i++)
        {
            WallList[i]->Repair();
        }

        for (int i = 0; i < SiegeList.size(); i++)
        {
            //SiegeList[i].Repair();
        }

        NeedSave = true;
    }

    void ConquestObject::TakeConquest(PlayerObject *player, GuildObject *winningGuild)
    {
        if (winningGuild == nullptr && (player == nullptr || player->MyGuild == nullptr || player->MyGuild->Conquest != nullptr))
        {
            return;
        }
        if (winningGuild != nullptr && winningGuild->Conquest != nullptr)
        {
            return;
        }
        if (player != nullptr && player->MyGuild != nullptr && player->MyGuild->Conquest != nullptr)
        {
            return;
        }

        GuildObject *tmpPrevious = nullptr;

        switch (GameType)
        {
            case ConquestGame::CapturePalace:
                if (player == nullptr)
                {
                    return;
                }
                if (StartType == ConquestType::Request)
                {
                    if (player->MyGuild->Guildindex != AttackerID)
                    {
                        break;
                    }
                }

                if (Guild != nullptr)
                {
                    tmpPrevious = Guild;
                    Guild->Conquest = nullptr;
                    AttackerID = tmpPrevious->Guildindex;
                }

                Owner = player->MyGuild->Guildindex;
                Guild = player->MyGuild;
                player->MyGuild->Conquest = this;
                EndWar(GameType);
                break;
            case ConquestGame::KingOfHill:
            case ConquestGame::Classic:
                if (StartType == ConquestType::Request)
                {
                    if (winningGuild->Guildindex != AttackerID)
                    {
                        break;
                    }
                }

                if (Guild != nullptr)
                {
                    tmpPrevious = Guild;
                    Guild->Conquest = nullptr;
                    AttackerID = tmpPrevious->Guildindex;
                }

                Owner = winningGuild->Guildindex;
                Guild = winningGuild;
                Guild->Conquest = this;
                break;
            case ConquestGame::ControlPoints:
            {
                Owner = winningGuild->Guildindex;
                Guild = winningGuild;
                Guild->Conquest = this;

                std::vector<ConquestFlagObject*> keys(ControlPoints.Keys);
                for (auto key : keys)
                {
                    key->ChangeOwner(Guild);
                    ControlPoints[key] = std::unordered_map<GuildObject*, int>();
                }

                break;
            }
        }

        for (int i = 0; i < FlagList.size(); i++)
        {
            FlagList[i]->Guild = Guild;
            FlagList[i]->UpdateImage();
            FlagList[i]->UpdateColour();
        }

        if (Guild != nullptr)
        {
            UpdatePlayers(Guild);
            if (tmpPrevious != nullptr)
            {
                UpdatePlayers(tmpPrevious);
            }
            NeedSave = true;
        }
    }

    void ConquestObject::UpdatePlayers(GuildObject *tempGuild)
    {
        PlayerObject *player = nullptr;
        Packet *p;

        for (int i = 0; i < tempGuild->Ranks.size(); i++)
        {
            for (int j = 0; j < tempGuild->Ranks[i]->Members->size(); j++)
            {
                player = std::any_cast<PlayerObject*>(tempGuild->Ranks[i]->Members[j].Player);
                if (player != nullptr)
                {
                    tempGuild->SendGuildStatus(player);
                    p = new ServerPackets::ObjectGuildNameChanged();
                    p->ObjectID = player->ObjectID;
                    p->GuildName = player->MyGuild->GetName();
                    BroadcastGuildName(player, p);
                }
            }
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete p' statement was not added since p was passed to a method or constructor. Handle memory management manually.
    }

    void ConquestObject::BroadcastGuildName(PlayerObject *player, Packet *p)
    {
        if (player->getCurrentMap() == nullptr)
        {
            return;
        }

        for (int i = player->getCurrentMap()->Players.size() - 1; i >= 0; i--)
        {
            PlayerObject *tempPlayer = player->getCurrentMap()->Players[i];
            if (tempPlayer == player)
            {
                continue;
            }

            if (Functions::InRange(player->getCurrentLocation(), tempPlayer->getCurrentLocation(), Globals::DataRange))
            {
                if (p != nullptr)
                {
                    tempPlayer->Enqueue(p);
                }
            }
        }
    }

    void ConquestObject::CreateZone(bool Create)
    {
        if (Create)
        {
            WarEffects.clear();
            for (int y = Info->KingLocation->Y - Info->KingSize; y <= Info->KingLocation->Y + Info->KingSize; y++)
            {
                if (y < 0)
                {
                    continue;
                }
                if (y >= ConquestMap->Height)
                {
                    break;
                }
                for (int x = Info->KingLocation->X - Info->KingSize; x <= Info->KingLocation->X + Info->KingSize; x += std::abs(y - Info->KingLocation->Y) == Info->KingSize ? 1 : Info->KingSize * 2)
                {
                    if (x < 0)
                    {
                        continue;
                    }
                    if (x >= ConquestMap->Width)
                    {
                        break;
                    }
                    if (!ConquestMap->Cells[x][y].Valid)
                    {
                        continue;
                    }

                    SpellObject *spell = new SpellObject();
                    spell->ExpireTime = std::numeric_limits<long long>::max();
                    spell->Spell = Spell::TrapHexagon;
                    spell->TickSpeed = std::numeric_limits<int>::max();
                    Point tempVar(x, y);
                    spell->setCurrentLocation(&tempVar);
                    spell->setCurrentMap(ConquestMap);
                    spell->Decoration = true;

                    ConquestMap->Cells[x][y].push_back(spell);
                    WarEffects.push_back(spell);
                    spell->Spawned();

//C# TO C++ CONVERTER TODO TASK: A 'delete spell' statement was not added since spell was passed to a method or constructor. Handle memory management manually.
                }
            }
        }
        else
        {
            for (int i = 0; i < WarEffects.size(); i++)
            {
                //if (WarEffects[i].CurrentLocation != null)
                //{
                    WarEffects[i]->Despawn();
                    ConquestMap->RemoveObject(WarEffects[i]);
                //}                

            }
            WarEffects.clear();
        }

    }

    void ConquestObject::ScorePoints()
    {
        bool PointsChanged = false;

        switch (GameType)
        {
            case ConquestGame::ControlPoints:
            {
                    int points;

                    for (auto item : ControlPoints)
                    {
                        PointsChanged = false;

                        ConquestFlagObject *controlFlag = nullptr;
                        std::unordered_map<GuildObject*, int> controlFlagPoints;

                        for (int i = 0; i < ConquestMap->Players.size(); i++)
                        {
                            if (!ConquestMap->Players[i]->WarZone || ConquestMap->Players[i]->MyGuild == nullptr || ConquestMap->Players[i]->Dead)
                            {
                                continue;
                            }

                            controlFlag = item.first;
                            controlFlagPoints = item.second;

                            if (!Functions::InRange(controlFlag->Info->Location, ConquestMap->Players[i]->getCurrentLocation(), 3))
                            {
                                continue;
                            }

                            std::unordered_map<GuildObject*, int>::const_iterator controlFlagPoints_iterator = controlFlagPoints.find(ConquestMap->Players[i]->MyGuild);
                            points = controlFlagPoints_iterator->second;

                            if (points == 0)
                            {
                                controlFlagPoints[ConquestMap->Players[i]->MyGuild] = 1;
                                ConquestMap->Players[i]->MyGuild.SendOutputMessage(std::string::Format("Gaining control of {1} {0:P0}", (static_cast<double>(controlFlagPoints[ConquestMap->Players[i]->MyGuild]) / MAX_CONTROL_POINTS), controlFlag->Info->Name));
                            }
                            else if (points < MAX_CONTROL_POINTS)
                            {
                                controlFlagPoints[ConquestMap->Players[i]->MyGuild] += 1;
                                ConquestMap->Players[i]->MyGuild.SendOutputMessage(std::string::Format("Gaining control of {1} {0:P0}", (static_cast<double>(controlFlagPoints[ConquestMap->Players[i]->MyGuild]) / MAX_CONTROL_POINTS), controlFlag->Info->Name));
                            }

                            std::vector<GuildObject*> guilds = controlFlagPoints.Keys->ToList();
                            for (auto guild : guilds)
                            {
                                if (ConquestMap->Players[i]->MyGuild == guild)
                                {
                                    continue;
                                }
                                std::unordered_map<GuildObject*, int>::const_iterator controlFlagPoints_iterator = controlFlagPoints.find(ConquestMap->Players[i]->MyGuild);
                                points = controlFlagPoints_iterator->second;
                                if (controlFlagPoints[guild] > 0)
                                {
                                    controlFlagPoints[guild] -= 1;
                                }
                            }

                            PointsChanged = true;
                        }

                        if (PointsChanged)
                        {
                            GuildObject *tempWinning = Guild;
                            int tempInt;

                            //Check Scores
                            for (int i = 0; i < getEnvir()->GuildList.size(); i++)
                            {
                                std::unordered_map<GuildObject*, int>::const_iterator controlFlagPoints_iterator = controlFlagPoints.find(getEnvir()->GuildList[i]);
                                points = controlFlagPoints_iterator->second;
                                if (tempWinning != nullptr)
                                {
                                    std::unordered_map<GuildObject*, int>::const_iterator controlFlagPoints_iterator = controlFlagPoints.find(tempWinning);
                                    tempInt = controlFlagPoints_iterator->second;
                                }
                                else
                                {
                                    tempInt = 0;
                                }

                                if (points > tempInt)
                                {
                                    tempWinning = getEnvir()->GuildList[i];
                                }
                            }

                            if (tempWinning != controlFlag->Guild)
                            {
                                controlFlag->ChangeOwner(tempWinning);

                                for (int j = 0; j < ConquestMap->Players.size(); j++)
                                {
                                    ConquestMap->Players[j]->ReceiveChat(StringHelper::formatSimple("{0} has captured {1} at {2}", tempWinning->Name, controlFlag->Info->Name, Info->Name), ChatType::System);
                                }
                            }
                        }
                    }
            }
                break;
            case ConquestGame::KingOfHill:
            {
                    int points;

                    for (int i = 0; i < ConquestMap->Players.size(); i++)
                    {
                        if (ConquestMap->Players[i]->WarZone && ConquestMap->Players[i]->MyGuild != nullptr && !ConquestMap->Players[i]->Dead && Functions::InRange(Info->KingLocation, ConquestMap->Players[i]->getCurrentLocation(), Info->KingSize))
                        {
                            if (StartType == ConquestType::Request && ConquestMap->Players[i]->MyGuild.Guildindex != AttackerID)
                            {
                                continue;
                            }

                            if (ConquestMap->Players[i]->MyGuild.Conquest != nullptr && ConquestMap->Players[i]->MyGuild.Conquest != this)
                            {
                                continue;
                            }

                            std::unordered_map<GuildObject*, int>::const_iterator KingPoints_iterator = KingPoints.find(ConquestMap->Players[i]->MyGuild);
                            points = KingPoints_iterator->second;

                            if (points == 0)
                            {
                                KingPoints[ConquestMap->Players[i]->MyGuild] = 1;
                                ConquestMap->Players[i]->MyGuild.SendOutputMessage(std::string::Format("Gaining control of {1} {0:P0}", (static_cast<double>(KingPoints[ConquestMap->Players[i]->MyGuild]) / MAX_KING_POINTS), Info->Name));
                            }
                            else if (points < MAX_KING_POINTS)
                            {
                                KingPoints[ConquestMap->Players[i]->MyGuild] += 1;
                                ConquestMap->Players[i]->MyGuild.SendOutputMessage(std::string::Format("Gaining control of {1} {0:P0}", (static_cast<double>(KingPoints[ConquestMap->Players[i]->MyGuild]) / MAX_KING_POINTS), Info->Name));
                            }

                            std::vector<GuildObject*> guilds = KingPoints.Keys->ToList();
                            for (auto guild : guilds)
                            {
                                if (ConquestMap->Players[i]->MyGuild == guild)
                                {
                                    continue;
                                }
                                std::unordered_map<GuildObject*, int>::const_iterator KingPoints_iterator = KingPoints.find(ConquestMap->Players[i]->MyGuild);
                                points = KingPoints_iterator->second;
                                if (KingPoints[guild] > 0)
                                {
                                    KingPoints[guild] -= 1;
                                    guild->SendOutputMessage(std::string::Format("Losing control of {1} {0:P0}", (static_cast<double>(KingPoints[guild]) / MAX_KING_POINTS), Info->Name));
                                }
                            }

                            PointsChanged = true;
                        }
                    }

                    if (PointsChanged)
                    {
                        GuildObject *tempWinning = Guild;
                        int tempInt;

                        //Check Scores
                        for (int i = 0; i < getEnvir()->GuildList.size(); i++)
                        {
                            std::unordered_map<GuildObject*, int>::const_iterator KingPoints_iterator = KingPoints.find(getEnvir()->GuildList[i]);
                            points = KingPoints_iterator->second;
                            if (tempWinning != nullptr)
                            {
                                std::unordered_map<GuildObject*, int>::const_iterator KingPoints_iterator = KingPoints.find(tempWinning);
                                tempInt = KingPoints_iterator->second;
                            }
                            else
                            {
                                tempInt = 0;
                            }

                            if (points > tempInt)
                            {
                                tempWinning = getEnvir()->GuildList[i];
                            }
                        }

                        if (tempWinning != Guild)
                        {
                            TakeConquest(nullptr, tempWinning);

                            for (int j = 0; j < ConquestMap->Players.size(); j++)
                            {
                                ConquestMap->Players[j]->ReceiveChat(StringHelper::formatSimple("{0} has captured the hill", tempWinning->Name), ChatType::System);
                            }
                        }
                    }
            }
                break;
            case ConquestGame::Classic:
            {
                int GuildCounter = 0;
                GuildObject *TakingGuild = nullptr;
                for (int i = 0; i < PalaceMap->Players.size(); i++)
                {
                    if (PalaceMap->Players[i]->Dead)
                    {
                        continue;
                    }

                    if (PalaceMap->Players[i]->MyGuild != nullptr)
                    {
                        if (TakingGuild == nullptr || TakingGuild != PalaceMap->Players[i]->MyGuild)
                        {
                            GuildCounter++;
                        }

                        TakingGuild = PalaceMap->Players[i]->MyGuild;
                    }
                    else
                    {
                        GuildCounter++;
                    }
                }

                if (GuildCounter == 1 && TakingGuild != Guild)
                {
                    if (StartType == ConquestType::Request && TakingGuild->Guildindex != AttackerID)
                    {
                        return;
                    }

                    TakeConquest(nullptr, TakingGuild);
                }

                break;


            }
            default:
                return;
        }



    }

    void ConquestObject::StartWar(ConquestGame type)
    {
        setWarIsOn(true);
    }

    void ConquestObject::EndWar(ConquestGame type)
    {
        setWarIsOn(false);

        switch (type)
        {
            case ConquestGame::ControlPoints:
            {
                std::unordered_map<GuildObject*, int> controlledPoints;
                int count = 0;

                for (auto item : ControlPoints)
                {
                    std::unordered_map<GuildObject*, int>::const_iterator controlledPoints_iterator = controlledPoints.find(item.first::Guild);
                    count = controlledPoints_iterator->second;

                    if (count == 0)
                    {
                        controlledPoints[item.first::Guild] = 1;
                    }
                    else
                    {
                        controlledPoints[item.first::Guild] += 1;
                    }
                }

                GuildObject *tempWinning = Guild;
                int tempInt;

                std::vector<GuildObject*> guilds = controlledPoints.Keys->ToList();

                //Check Scores
                for (int i = 0; i < guilds.size(); i++)
                {
                    std::unordered_map<GuildObject*, int>::const_iterator controlledPoints_iterator = controlledPoints.find(guilds[i]);
                    count = controlledPoints_iterator->second;
                    if (tempWinning != nullptr)
                    {
                        std::unordered_map<GuildObject*, int>::const_iterator controlledPoints_iterator = controlledPoints.find(tempWinning);
                        tempInt = controlledPoints_iterator->second;
                    }
                    else
                    {
                        tempInt = 0;
                    }

                    if (count > tempInt)
                    {
                        tempWinning = getEnvir()->GuildList[i];
                    }
                }

                TakeConquest(nullptr, tempWinning);

                break;
            }
        }
    }

    Server::MirEnvir::Envir *ConquestSiegeObject::getEnvir()
    {
        return Envir::getMain();
    }

    ConquestSiegeObject::ConquestSiegeObject()
    {

    }

    ConquestSiegeObject::ConquestSiegeObject(PlayerObject *owner, const std::string &name)
    {

    }

    ConquestSiegeObject::ConquestSiegeObject(BinaryReader *reader)
    {
        Index = reader->ReadInt32();

        if (Envir::LoadVersion <= 84)
        {
            Health = static_cast<int>(reader->ReadUInt32());
        }
        else
        {
            Health = reader->ReadInt32();
        }
    }

    void ConquestSiegeObject::Save(BinaryWriter *writer)
    {
        //if (Gate != null) Health = Gate.HP; - needs adding
        writer->Write(Index);
        writer->Write(Health);
    }

    void ConquestSiegeObject::Spawn()
    {
        if (Gate != nullptr)
        {
            Gate->Despawn();
        }

        MonsterInfo *monsterInfo = getEnvir()->GetMonsterInfo(Info->MobIndex);

        if (monsterInfo == nullptr)
        {
            return;
        }
        if (monsterInfo->AI != 72)
        {
            return;
        }

        if (monsterInfo->AI == 72)
        {
            Gate = static_cast<Gate*>(MonsterObject::GetMonster(monsterInfo));
        }
        else if (monsterInfo->AI == 73)
        {
            //Gate = (GateWest)MonsterObject.GetMonster(monsterInfo);


            if (Gate == nullptr)
            {
                return;
            }
        }

        Gate->Conquest = Conquest;
        Gate->GateIndex = Index;

        Gate->Spawn(Conquest->ConquestMap, Info->Location);

        if (Health == 0)
        {
            Gate->Die();
        }
        else
        {
            Gate->SetHP(Health);
        }

        Gate->CheckDirection();
    }

    int ConquestSiegeObject::GetRepairCost()
    {
        int cost = 0;

        if (Gate == nullptr)
        {
            return 0;
        }

        if (Gate->Stats[Stat::HP] == Gate->HP)
        {
            return cost;
        }

        if (Info->RepairCost != 0)
        {
            cost = Info->RepairCost / (Gate->Stats[Stat::HP] / (Gate->Stats[Stat::HP] - Gate->HP));
        }

        return cost;
    }

    void ConquestSiegeObject::Repair()
    {
        if (Gate == nullptr)
        {
            Spawn();
            return;
        }

        if (Gate->Dead)
        {
            Spawn();
        }
        else
        {
            Gate->HP = Gate->Stats[Stat::HP];
        }

        Gate->CheckDirection();


    }

    ConquestFlagObject::ConquestFlagObject()
    {

    }

    void ConquestFlagObject::Spawn()
    {
        NPCInfo *npcInfo = new NPCInfo();
        npcInfo->Name = Info->Name;
        npcInfo->FileName = Info->FileName;
        npcInfo->Location = Info->Location;
        npcInfo->Image = 1000;

        if (Conquest->Guild != nullptr)
        {
            Guild = Conquest->Guild;
            npcInfo->Image = Guild->FlagImage;
            npcInfo->Colour = Guild->FlagColour;
        }

        Flag = new NPCObject(npcInfo);
        Flag->setCurrentMap(Conquest->ConquestMap);

        Flag->getCurrentMap()->AddObject(Flag);

        Flag->Spawned();

//C# TO C++ CONVERTER TODO TASK: A 'delete npcInfo' statement was not added since npcInfo was passed to a method or constructor. Handle memory management manually.
    }

    void ConquestFlagObject::ChangeOwner(GuildObject *guild)
    {
        Guild = guild;

        UpdateImage();
        UpdateColour();
    }

    void ConquestFlagObject::UpdateImage()
    {
        if (Guild != nullptr)
        {
            Flag->Info->Image = Guild->FlagImage;

            Flag->Broadcast(Flag->GetUpdateInfo());
        }
    }

    void ConquestFlagObject::UpdateColour()
    {
        if (Guild != nullptr)
        {
            Flag->Info->Colour = Guild->FlagColour;

            Flag->Broadcast(Flag->GetUpdateInfo());
        }
    }

    Server::MirEnvir::Envir *ConquestWallObject::getEnvir()
    {
        return Envir::getMain();
    }

    ConquestWallObject::ConquestWallObject()
    {

    }

    ConquestWallObject::ConquestWallObject(PlayerObject *owner, const std::string &name)
    {

    }

    ConquestWallObject::ConquestWallObject(BinaryReader *reader)
    {
        Index = reader->ReadInt32();

        if (Envir::LoadVersion <= 84)
        {
            Health = static_cast<int>(reader->ReadUInt32());
        }
        else
        {
            Health = reader->ReadInt32();
        }
    }

    void ConquestWallObject::Save(BinaryWriter *writer)
    {
        if (Wall != nullptr)
        {
            Health = Wall->HP;
        }
        writer->Write(Index);
        writer->Write(Wall->getHealth());
    }

    void ConquestWallObject::Spawn(bool repair)
    {
        if (Wall != nullptr)
        {
            Wall->Despawn();
        }

        MonsterInfo *monsterInfo = getEnvir()->GetMonsterInfo(Info->MobIndex);

        if (monsterInfo == nullptr)
        {
            return;
        }

        if (monsterInfo->AI != 82)
        {
            return;
        }

        Wall = static_cast<Wall*>(MonsterObject::GetMonster(monsterInfo));

        if (Wall == nullptr)
        {
            return;
        }

        Wall->Conquest = Conquest;
        Wall->WallIndex = Index;

        Wall->Spawn(Conquest->ConquestMap, Info->Location);

        if (repair)
        {
            Health = Wall->Stats[Stat::HP];
        }

        if (Health == 0)
        {
            Wall->Die();
        }
        else
        {
            Wall->SetHP(Health);
        }

        Wall->CheckDirection();
    }

    int ConquestWallObject::GetRepairCost()
    {
        int cost = 0;

        if (Wall == nullptr)
        {
            return 0;
        }

        if (Wall->Stats[Stat::HP] == Wall->HP)
        {
            return cost;
        }

        if (Info->RepairCost != 0)
        {
            cost = Info->RepairCost / (Wall->Stats[Stat::HP] / (Wall->Stats[Stat::HP] - Wall->HP));
        }

        return cost;
    }

    void ConquestWallObject::Repair()
    {
        if (Wall == nullptr)
        {
            Spawn(true);
            return;
        }

        if (Wall->Dead)
        {
            Spawn(true);
        }
        else
        {
            Wall->HP = Wall->Stats[Stat::HP];
        }

        Wall->CheckDirection();
    }

    Server::MirEnvir::Envir *ConquestGateObject::getEnvir()
    {
        return Envir::getMain();
    }

    ConquestGateObject::ConquestGateObject()
    {

    }

    ConquestGateObject::ConquestGateObject(PlayerObject *owner, const std::string &name)
    {

    }

    ConquestGateObject::ConquestGateObject(BinaryReader *reader)
    {
        Index = reader->ReadInt32();

        if (Envir::LoadVersion <= 84)
        {
            Health = static_cast<int>(reader->ReadUInt32());
        }
        else
        {
            Health = reader->ReadInt32();
        }
    }

    void ConquestGateObject::Save(BinaryWriter *writer)
    {
        if (Gate != nullptr)
        {
            Health = Gate->HP;
        }
        writer->Write(Index);
        writer->Write(Health);
    }

    void ConquestGateObject::Spawn(bool repair)
    {
        if (Gate != nullptr)
        {
            Gate->Despawn();
        }

        MonsterInfo *monsterInfo = getEnvir()->GetMonsterInfo(Info->MobIndex);

        if (monsterInfo == nullptr)
        {
            return;
        }
        if (monsterInfo->AI != 81)
        {
            return;
        }

        Gate = static_cast<Gate*>(MonsterObject::GetMonster(monsterInfo));

        if (Gate == nullptr)
        {
            return;
        }

        Gate->Conquest = Conquest;
        Gate->GateIndex = Index;

        Gate->Spawn(Conquest->ConquestMap, Info->Location);

        if (repair)
        {
            Health = Gate->Stats[Stat::HP];
        }

        if (Health == 0)
        {
            Gate->Die();
        }
        else
        {
            Gate->SetHP(Health);
        }

        Gate->CheckDirection();
    }

    int ConquestGateObject::GetRepairCost()
    {
        int cost = 0;

        if (Gate == nullptr)
        {
            return 0;
        }

        if (Gate->Stats[Stat::HP] == Gate->HP)
        {
            return cost;
        }

        if (Info->RepairCost != 0)
        {
            cost = Info->RepairCost / (Gate->Stats[Stat::HP] / (Gate->Stats[Stat::HP] - Gate->HP));
        }

        return cost;
    }

    void ConquestGateObject::Repair()
    {
        if (Gate == nullptr)
        {
            Spawn(true);
            return;
        }

        if (Gate->Dead)
        {
            Spawn(true);
        }
        else
        {
            Gate->HP = Gate->Stats[Stat::HP];
        }

        Gate->CheckDirection();


    }

    Server::MirEnvir::Envir *ConquestArcherObject::getEnvir()
    {
        return Envir::getMain();
    }

    ConquestArcherObject::ConquestArcherObject()
    {

    }

    ConquestArcherObject::ConquestArcherObject(PlayerObject *owner, const std::string &name)
    {

    }

    ConquestArcherObject::ConquestArcherObject(BinaryReader *reader)
    {
        Index = reader->ReadInt32();
        Alive = reader->ReadBoolean();
    }

    void ConquestArcherObject::Save(BinaryWriter *writer)
    {
        if (ArcherMonster == nullptr || ArcherMonster->Dead)
        {
            Alive = false;
        }
        else
        {
            Alive = true;
        }
        writer->Write(Index);
        writer->Write(Alive);
    }

    void ConquestArcherObject::Spawn(bool Revive)
    {
        if (Revive)
        {
            Alive = true;
        }

        MonsterInfo *monsterInfo = getEnvir()->GetMonsterInfo(Info->MobIndex);

        if (monsterInfo == nullptr)
        {
            return;
        }
        if (monsterInfo->AI != 80)
        {
            return;
        }

        ArcherMonster = static_cast<ConquestArcher*>(MonsterObject::GetMonster(monsterInfo));

        if (ArcherMonster == nullptr)
        {
            return;
        }

        ArcherMonster->Conquest = Conquest;
        ArcherMonster->ArcherIndex = Index;

        if (Alive)
        {
            ArcherMonster->Spawn(Conquest->ConquestMap, Info->Location);
        }
        else
        {
            ArcherMonster->Spawn(Conquest->ConquestMap, Info->Location);
            ArcherMonster->Die();
            ArcherMonster->DeadTime = getEnvir()->getTime();
        }
    }

    unsigned int ConquestArcherObject::GetRepairCost()
    {
        unsigned int cost = 0;

        if (ArcherMonster == nullptr || ArcherMonster->Dead)
        {
            cost = Info->RepairCost;
        }

        return cost;
    }
}
